package plgbase

import (
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/subpub"
	"gitee.com/ymofen/supervalue"
	"io"
	"sync/atomic"
)

const (
	STATUS_INIT   int32 = 0
	STATUS_OK     int32 = 1
	STATUS_CLOSED int32 = -1
	STATUS_FAIL   int32 = -2
)

type PlgBaseSub struct {
	statuscode       int32
	subSessionPrefix string
	subsessionid     string
	subconnstr       string
	stepMsg          string
	errmsg           string
}

var (
	subsessionN int32
)

// subprefix 创建session时的前缀
func NewPlgBaseSub(subprefix string) *PlgBaseSub {
	rval := &PlgBaseSub{subSessionPrefix: subprefix, statuscode: 0}
	return rval
}

func (this *PlgBaseSub) GetSubSessionID() string {
	return this.subsessionid
}

func (this *PlgBaseSub) ConfString() string {
	return this.subconnstr
}

// 0: 未初始化
// 1: 正常
// -1: 已经关闭
// -3: 加载出错
func (this *PlgBaseSub) StatusCode() int32 {
	return this.statuscode
}

func (this *PlgBaseSub) StatusText() string {
	return fmt.Sprintf("%d:%s, step:%s", this.statuscode, this.ConfString(), this.stepMsg)
}

func (this *PlgBaseSub) closeSub() {
	if len(this.subsessionid) > 0 {
		this.stepMsg = fmt.Sprintf("[%s]closeSub->DelSession:0", utils.NowString())
		subpub.DefaultSub.DelSession(this.subsessionid)
		this.stepMsg = fmt.Sprintf("[%s]closeSub->DelSession:1", utils.NowString())
		this.subsessionid = ""
		this.subconnstr = ""
		this.statuscode = STATUS_CLOSED
	}
}

func (this *PlgBaseSub) Close() error {
	if len(this.subsessionid) == 0 {
		return io.ErrClosedPipe
	}
	this.closeSub()
	return nil
}

func (this *PlgBaseSub) GetStepMsg() string {
	return this.stepMsg
}

func (this *PlgBaseSub) ReloadConnConfString(str string, notify subpub.SubFunc) error {
	if str != this.subconnstr {
		confMap := gobase.NewStrMap()
		this.closeSub()
		this.subconnstr = str
		confMap.URLFormDecode(str)

		if len(this.subsessionid) == 0 {
			this.subsessionid = fmt.Sprintf("%s-%d", this.subSessionPrefix, atomic.AddInt32(&subsessionN, 1))
		}
		this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:0", utils.NowString())
		err := subpub.DefaultSub.AddSession(this.subsessionid, confMap, notify)
		if err != nil {
			this.statuscode = STATUS_FAIL
			this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:-1, err:%s", utils.NowString(), err.Error())
			return err
		} else {
			this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:1", utils.NowString())
			this.statuscode = STATUS_OK
			return nil
		}
	}
	return nil
}

func (this *PlgBaseSub) ReloadConf(conf *wrapper.SuperValue, onsub subpub.SubFunc) error {
	if conf == nil {
		this.closeSub()
		return nil
	}

	confMap := gobase.NewStrMap()
	str := conf.String()
	if str != this.subconnstr {
		this.closeSub()
		this.subconnstr = str
		if conf.IsString() {
			confMap.URLFormDecode(str)
		} else if conf.IsObject() {
			url := conf.StringByName("url", "")
			if len(url) > 0 {
				confMap.URLFormDecode(url)
			}
			conf.Range(func(key string, val *wrapper.SuperValue) bool {
				confMap[key] = val.String()
				return true
			})
		}

		if len(this.subsessionid) == 0 {
			this.subsessionid = fmt.Sprintf("%s-%d", this.subSessionPrefix, atomic.AddInt32(&subsessionN, 1))
		}
		this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:0", utils.NowString())
		err := subpub.DefaultSub.AddSession(this.subsessionid, confMap, onsub)
		if err != nil {
			this.statuscode = STATUS_FAIL
			this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:-1, err:%s", utils.NowString(), err.Error())
			return err
		} else {
			this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:1", utils.NowString())
			this.statuscode = STATUS_OK
			return nil
		}
	}
	return nil
}
